using System;
using System.Collections.Generic;
using System.Text;
using JobShopModel.Model.FactoryLvl;
using JobShopModel.Model.Transport;
using JobShopModel.Model.JobLvl;
using JobShopModel.Model.Station;
using JobShopModel.Model;

namespace JobShopModel.Events
{
    /// <summary>
    /// Event Class:
    /// Called after an operation have been done by a station (Creation or Operation)
    /// <para>
    /// It will call a transporter
    /// If it is iddle
    ///     take the first job from its list
    ///     go to the station if needed
    ///     change the state of the station to iddle again
    ///     Send an event: PerformOperation to make the station working again
    ///     transport the job to its next station
    ///     Send an event: EndTransport to finish transporting in the future
    /// </para> 
    /// </summary>
    public class RequestTransport : TransportEvent
    {

        /// <summary>
        /// Default COnstructor
        /// </summary>
        /// <param name="sTime">Time to be started</param>
        /// 
        public RequestTransport(Time sTime)
            : base(sTime)
        {
        }

        /// <summary>
        /// Polymorphic method
        /// It will be instanced by all Events and excecuted by the eventloop
        /// </summary>
        public override void Process()
        {
            Factory fact = Factory.getInstance();
            Time elapsedTime = new Time();
            
            //If the transporter is IDDLE (Have finished working)
            if (fact.Transporter.State == TransportStates.IDDLE)
            {
                //Logger.InsertElement(new LogItem(ItemPriorities.VERBOSE, fact.CurrentTime, "Transporter have been requested by " + StartPosition));
                Transporter.EndIddle(fact.CurrentTime);

                /*Get the first element on the FIFO list.
                 * If their is nothing in the list, set the transport to IDDLE and wait...
                 * Else do the transportation then check again if transport.
                 */
                if (Transporter.isEmpty())
                {
                    Logger.InsertElement(new LogItem(ItemPriorities.NORMAL,fact.CurrentTime,"Transporter is going to IDLE"));
                    Transporter.StartIddle(fact.CurrentTime);
                }
                else
                {   //Get the job from the FIFO list
                    Job job = Transporter.GetJob();
                    StationsName iniPos = Transporter.Position;
                    StationsName jobPos = job.Position;

                    //Check where is the transporter
                    // If not at position, put it in position
                    if (Transporter.Position != job.Position)
                    {
                        Logger.InsertElement(new LogItem(ItemPriorities.SLOW,fact.CurrentTime,"Transporter is not at the right station, moving from: "+ Transporter.Position + " to " + job.Position));
                        //make the transporter move
                        Time arrivalTime = Transporter.TravelTo(job.Position);
                        elapsedTime = elapsedTime + arrivalTime;
                    }

                    //Unblock the current station by setting the machine used for the job back to IDDLE
                    if (job.Position != StationsName.IOSTATION)
                    {                    
                        UnBlockStation nextEvent = new UnBlockStation(fact.CurrentTime + elapsedTime, job.Position,job);
                        fact.EventQueue.insertEvent(nextEvent);
                        Logger.InsertElement(new LogItem(ItemPriorities.SLOW,fact.CurrentTime,"Unblocking the previous station"));
                        Logger.InsertElement(new LogItem(ItemPriorities.CREATION, fact.CurrentTime, "The Transporter inserted: \"" + nextEvent.ToString() + "\""));
                    }
                    else
                    {
                        //Select the next Operation to be done.
                        job.SelectNextOperation();

                        //Get the next destination from the newly set operation
                        StationsName destination = job.CurrentOperation.Station;

                        //Transport to station
                        Time transportTime = Transporter.TravelTo(destination);
                        Logger.InsertElement(new LogItem(ItemPriorities.SLOW, fact.CurrentTime + elapsedTime, "Transporting to station " + destination + "..."));
                        //Update time spent
                        Time elapsedTime2 = elapsedTime + transportTime;

                        //Call EndTransport Event to set transporter IDDLE at the correct time.
                        EndTransport secondEvent = new EndTransport(fact.CurrentTime + elapsedTime2, destination, job);
                        fact.EventQueue.insertEvent(secondEvent);
                        Logger.InsertElement(new LogItem(ItemPriorities.CREATION, fact.CurrentTime + elapsedTime, "The Transporter inserted: \"" + secondEvent.ToString() + "\""));

                    }
                }
            }
            else
            {
                Logger.InsertElement(new LogItem(ItemPriorities.NORMAL,fact.CurrentTime,"Transporter is not availlable"));
            }
        }

        public override string ToString()
        {
            return "Request_Transport ("+ExecTime+")";
        }

    }


}
